<?php
/**
 * @name Debug.php
 *
 * @link 
 * LICENSE
 *
 * This source file is subject to the BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.phpxe.com/license/
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to Davy <scd113@gmail.com> so we can send you a copy immediately.
 *
 * @category   Util
 * @package    Scd
 * @copyright  Copyright (c) 2007 PHPXE Web Studio (http://www.phpxe.com)
 * @license    http://framework.phpxe.com/license/     
 * @version    $Id: Debug.php Thu Aug 23 11:28:09 CST 2007 11:28:09 Administrator $
 */
require_once 'Scd/Util/Exception.php';
class Scd_Util_Debug{

}
/* used for tracking of generation-time */
$MICROTIME_START = microtime();
@$GLOBALS_initial_count = count($GLOBALS);
reset_script_runtime();
class Print_a_class {

	# this can be changed to true if you want
	var $look_for_leading_tabs = false;

	var $output;
	var $iterations;
	var $key_bg_color = '1E32C8';
	var $value_bg_color = 'DDDDEE';
	var $fontsize = '8pt';
	var $keyalign = 'left';
	var $fontfamily = 'Verdana';
	var $show_object_vars;
	var $limit;

	// function Print_a_class() {}

	# recursive function!

	/* this internal function looks if the given array has only numeric values as  */
	function _only_numeric_keys( $array ) {
		$test = true;
		if (is_array($array)) {
			foreach ( array_keys( $array ) as $key ) {
				if( !is_numeric( $key ) )   $test = false; /* #TODO# */
			}

			return $test;
		} else {
			return false;
		}
	}

	function _handle_whitespace( $string ) {
		$string = str_replace(' ', '&nbsp;', $string);
		$string = preg_replace(array('/&nbsp;$/', '/^&nbsp;/'), '<span style="color:red;">_</span>', $string); /* replace spaces at the start/end of the STRING with red underscores */
		$string = preg_replace('/\t/', '&nbsp;&nbsp;<span style="border-bottom:#'.$this->value_bg_color.' solid 1px;">&nbsp;</span>', $string); /* replace tabulators with '_ _' */

		return $string;
	}

	function print_a($array, $iteration = false, $key_bg_color = false) {
		$key_bg_color or $key_bg_color = $this->key_bg_color;

		# lighten up the background color for the key td's =)
		if( $iteration ) {
			for ($i=0; $i<6; $i+=2) {
				$c = substr( $key_bg_color, $i, 2 );
				$c = hexdec( $c );
				( $c += 15 ) > 255 and $c = 255;
				isset($tmp_key_bg_color) or $tmp_key_bg_color = '';
				$tmp_key_bg_color .= sprintf( "%02X", $c );
			}
			$key_bg_color = $tmp_key_bg_color;
		}

		# build a single table ... may be nested
		$this->output .= '<table style="border:none;" cellspacing="1">';
		$only_numeric_keys = ($this->_only_numeric_keys( $array ) || count( $array ) > 50);
		$i = 0;
		foreach ($array as $key => $value)
		{
			if( $only_numeric_keys && $this->limit && $this->limit == $i++ ) break; /* if print_a() was called with a fourth parameter #TODO# */

			$value_style_box = 'color:black;';
			$key_style = 'color:white;';

			$type = gettype( $value );
			# print $type.'<br />';

			# change the color and format of the value and set the values title
			$type_title = $type;
			$value_style_content = '';
			switch( $type ) {
				case 'array':
					if( empty( $value ) ) $type_title = 'empty array';
					break;

				case 'object':
					$key_style = 'color:#FF9B2F;';
					break;

				case 'integer':
					$value_style_box = 'color:green;';
					break;

				case 'double':
					$value_style_box = 'color:blue;';
					break;

				case 'boolean':
					if( $value == true ) {
						$value_style_box = 'color:#D90081;';
					} else {
						$value_style_box = 'color:#84009F;';
					}
					break;

				case 'NULL':
					$value_style_box = 'color:darkorange;';
					break;

				case 'string':
					if( $value == '' ) {

						$value_style_box = 'color:darkorange;';
						$value = "''";
						$type_title = 'empty string';

					} else {

						$value_style_box = 'color:black;';
						$value = htmlspecialchars( $value );
						if( $this->look_for_leading_tabs && _check_for_leading_tabs( $value ) ) {
							$value = _remove_exessive_leading_tabs( $value );
						}
						$value = $this->_handle_whitespace( $value );
						$value = nl2br($value);

						/* use different color for string background */
						if(strstr($value, "\n")) $value_style_content = 'background:#ECEDFE;';

					}
					break;
			}

			$this->output .= '<tr>';
			$this->output .= '<td nowrap="nowrap" align="'.$this->keyalign.'" style="padding:0px 3px 0px 3px;background-color:#'.$key_bg_color.';'.$key_style.';font:bold '.$this->fontsize.' '.$this->fontfamily.';" title="'.gettype( $key ).'['.$type_title.']">';
			$this->output .= $this->_handle_whitespace( $key );
			$this->output .= '</td>';
			$this->output .= '<td nowrap="nowrap" style="background-color:#'.$this->value_bg_color.';font: '.$this->fontsize.' '.$this->fontfamily.'; color:black;">';

			# value output
			if($type == 'array' && preg_match('/#RAS/', $key) ) { /* only used for special recursive array constructs which i use sometimes */
				$this->output .= '<div style="'.$value_style_box.'">recursion!</div>';
			} elseif($type == 'array') {
				if( ! empty( $value ) ) {
					$this->print_a( $value, true, $key_bg_color );
				} else {
					$this->output .= '<span style="color:darkorange;">[]</span>';
				}
			} elseif($type == 'object') {
				if( $this->show_object_vars ) {
					$objects_class = get_class($value);
					$this->print_a( array('CLASS_NAME' => $objects_class), true, '204FB8' );
					$this->print_a( array('CLASS_VARS' => get_class_vars( $objects_class )), true, '2066B8' );
					$this->print_a( array('CLASS_METHODS' => get_class_methods( $objects_class )), true, '2067EB8' );
					$this->print_a( array('OBJECT_VARS' => get_object_vars( $value )), true, '2095B8' );
				} else {
					$this->output .= '<div style="'.$value_style_box.'">OBJECT</div>';
				}
			} elseif($type == 'boolean') {
				$this->output .= '<div style="'.$value_style_box.'" title="'.$type.'">'.($value ? 'true' : 'false').'</div>';
			} elseif($type == 'NULL') {
				$this->output .= '<div style="'.$value_style_box.'" title="'.$type.'">NULL</div>';
			} else {
				$this->output .= '<div style="'.$value_style_box.'" title="'.$type.'"><span style="'.$value_style_content.'">'.$value.'</span></div>';
			}

			$this->output .= '</td>';
			$this->output .= '</tr>';
		}

		$entry_count = count( $array );
		$skipped_count = $entry_count - $this->limit;

		if( $only_numeric_keys && $this->limit && count($array) > $this->limit) {
			$this->output .= '<tr title="showing '.$this->limit.' of '.$entry_count.' entries in this array"><td style="text-align:right;color:darkgray;background-color:#'.$key_bg_color.';font:bold '.$this->fontsize.' '.$this->fontfamily.';">...</td><td style="background-color:#'.$this->value_bg_color.';font:'.$this->fontsize.' '.$this->fontfamily.';color:darkgray;">['.$skipped_count.' skipped]</td></tr>';
		}
		$this->output .= '</table>';
	}
}

# helper function.. calls print_a() inside the print_a_class
function print_a( $array, $mode = 0, $show_object_vars = false, $limit = false ) {
	$output = '';

	if( is_array( $array ) or is_object( $array ) ) {

		if( empty( $array ) ) {
			$output .= '<span style="color:red;font-size:small;">print_a( empty array )</span>';
		}

		$pa = &new Print_a_class;
		$show_object_vars and $pa->show_object_vars = true;
		if( $limit ) {
			$pa->limit = $limit;
			// $output .= '<span style="color:red;">showing only '.$limit.' entries for arrays with numeric keys</span>';
		}

		if ( is_object($array) ) {

			$pa->print_a( get_object_vars($array) );

		} else {

			$pa->print_a( $array );
		}

		# $output = $pa->output; unset($pa);
		$output .= $pa->output;
	} elseif( gettype($array) == 'boolean') {
		$output .= '<span style="color:red;font-size:small;">print_a( '.($array === true ? 'true' : 'false').' )</span>';
	} else {
		$output .= '<span style="color:red;font-size:small;">print_a( '.gettype( $array ).' )</span>';
	}

	if($mode === 0 || $mode == NULL || $mode == false) {
		print $output;
		return true;
	}

	if($mode == 1) {
		return $output;
	}

	if(is_string($mode) || $mode == 2 ) {
		$debugwindow_origin = $_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"];

		if(preg_match('/(.+)::(.+)/', $mode, $matches)) {
			$mode = $matches[1];
			$remote_addr = gethostbyname($matches[2]);
			if($_SERVER['REMOTE_ADDR'] != $remote_addr) return;
		}

		if(preg_match('/^_(.*)/', $mode, $matches)) {
			#$output = "<table style=\"border:1px solid black;\" cellpadding=\"0\" cellspcing=\"0\"><tr><td style=\"background:#1E2B9E;color:white;font-weight:bold;padding:2px;\">{$matches[1]}</td></tr><tr><td>$output</td></tr></table>";
			$output = "<fieldset style=\"width:100px;padding:2px;border:1px solid #666666;\"><legend>{$matches[1]}</legend>$output</fieldset><br />";

			print $output;
		} else {

			print '
                <script type="text/javascript" language="JavaScript">
                var debugwindow;
                debugwindow = window.open("", "T_'.md5($_SERVER['HTTP_HOST']).(is_string($mode)  ? $mode : '').'", "menubar=no,scrollbars=yes,resizable=yes,width=640,height=480");
                debugwindow.document.open();
                debugwindow.document.write("'.str_replace(array("\r\n", "\n", "\r"), '\n', addslashes($output)).'");
                debugwindow.document.close();
                debugwindow.document.title = "'.(is_string($mode) ? "($mode)" : '').' Debugwindow for : http://'.$debugwindow_origin.'";
                debugwindow.focus();
                </script>
                ';
		}
	}

	if($mode == 3) {
		print '
                <script type="text/javascript" language="JavaScript">
                    var debugwindow;
                    debugwindow = window.open("", "S_'.md5($_SERVER['HTTP_HOST']).'", "menubar=yes,scrollbars=yes,resizable=yes,width=640,height=480");
                    debugwindow.document.open();
                    debugwindow.document.write("unserialize(\''.str_replace("'", "\\'", addslashes( str_replace(array("\r\n", "\n", "\r"), '\n', serialize($array) ) ) ).'\');");
                    debugwindow.document.close();
                    debugwindow.document.title = "Debugwindow for : http://'.$debugwindow_origin.'";
                    debugwindow.focus();
                </script>
            ';
	}

}

/**
	 * @name print_result
	 * 
	 * @desc rs2html
	 * @param SQL $sql
	 */
function print_result($sql) {
	if(!$sql) return;
	if (!ereg('select', strtolower($sql))) {
		return new Scd_Util_Exception("I cann`t found `select` from sql !");
	}
	$RESULT = mysql_query($sql);
	if(mysql_num_rows($RESULT) < 1) return;
	$fieldcount = mysql_num_fields($RESULT);

	for ($i=0; $i<$fieldcount; $i++) {
		$tables[mysql_field_table($RESULT, $i)]++;
	}

	print '
            <style type="text/css">
                .rs_tb_th {
                    font-family: Verdana;
                    font-size:10pt;
                    font-weight:bold;
                    color:white;
                }
                .rs_f_th {
                    font-family:Verdana;
                    font-size:10pt;
                    font-weight:bold;
                    color:white;
                }
                .rs_td {
                    font-family:Verdana;
                    font-size:10pt;
                }
            </style>
            <script type="text/javascript" language="JavaScript">
                var lastID;
                function highlight(id) {
                    if(lastID) {
                        lastID.style.color = "#000000";
                        lastID.style.textDecoration = "none";
                    }
                    tdToHighlight = document.getElementById(id);
                    tdToHighlight.style.color ="#FF0000";
                    tdToHighlight.style.textDecoration = "underline";
                    lastID = tdToHighlight;
                }
            </script>
        ';

	print '<table bgcolor="#000000" cellspacing="1" cellpadding="1">';

	print '<tr>';
	foreach ($tables as $tableName => $tableCount) {
		$col == '0054A6' ? $col = '003471' : $col = '0054A6';
		print '<th colspan="'.$tableCount.'" class="rs_tb_th" style="background-color:#'.$col.';">'.$tableName.'</th>';
	}
	print '</tr>';

	print '<tr>';
	for ($i=0;$i < mysql_num_fields($RESULT);$i++) {
		$FIELD = mysql_field_name($RESULT, $i);
		$col == '0054A6' ? $col = '003471' : $col = '0054A6';
		print '<td align="center" bgcolor="#'.$col.'" class="rs_f_th">'.$FIELD.'</td>';
	}
	print '</tr>';

	mysql_data_seek($RESULT, 0);

	while ($DB_ROW = mysql_fetch_array($RESULT, MYSQL_NUM)) {
		$pointer++;
		if($toggle) {
			$col1 = "E6E6E6";
			$col2 = "DADADA";
		} else {
			$col1 = "E1F0FF";
			$col2 = "DAE8F7";
		}
		$toggle = !$toggle;
		print '<tr id="ROW'.$pointer.'" onMouseDown="highlight(\'ROW'.$pointer.'\');">';
		foreach ($DB_ROW as $value) {
			$col == $col1 ? $col = $col2 : $col = $col1;
			print '<td valign="top" bgcolor="#'.$col.'" class="rs_td" nowrap>'.nl2br($value).'</td>';
		}
		print '</tr>';
	}
	print '</table>';
	mysql_data_seek($RESULT, 0);
}

/**
 * @name reset the millisec timer
 *
 */
function reset_script_runtime() {
	$GLOBALS['MICROTIME_START'] = microtime();
}

/**
	 * @name function returns the milliseconds passed
	 */
function script_runtime() {
	$MICROTIME_END      = microtime();
	$MICROTIME_START    = explode(' ', $GLOBALS['MICROTIME_START']);
	$MICROTIME_END      = explode(' ', $MICROTIME_END);
	$GENERATIONSEC      = $MICROTIME_END[1] - $MICROTIME_START[1];
	$GENERATIONMSEC = $MICROTIME_END[0] - $MICROTIME_START[0];
	$GENERATIONTIME = substr($GENERATIONSEC + $GENERATIONMSEC, 0, 8);

	return (float) $GENERATIONTIME;
}

function _script_globals() {
	global $GLOBALS_initial_count;

	$varcount = 0;

	foreach ($GLOBALS as $GLOBALS_current_key => $GLOBALS_current_value) {
		if(++$varcount > $GLOBALS_initial_count) {
			/* die wollen wir nicht! */
			if ($GLOBALS_current_key != 'HTTP_SESSION_VARS' && $GLOBALS_current_key != '_SESSION') {
				$script_GLOBALS[$GLOBALS_current_key] = $GLOBALS_current_value;
			}
		}
	}

	unset($script_GLOBALS['GLOBALS_initial_count']);
	return $script_GLOBALS;
}

/**
	 * @name show_vars
	 * 
	 * function shows all superglobals and script defined global variables
	 * show_vars() without the first parameter shows all superglobals except $_ENV and $_SERVER
	 * show_vars(1) shows all
	 * show_vars(#,1) shows object properties in addition
	 * @param boolen $show_all_vars
	 * @param boolen $show_object_vars
	 * @param string $limit
	 */
function show_vars($show_all_vars = false, $show_object_vars = false, $limit = 5) {
	if($limit === 0) $limit = false;

	if(isset($GLOBALS['no_vars'])) return;

	$script_globals = _script_globals();
	print '
            <style type="text/css" media="screen">
                .vars-container {
                    font-family: Verdana, Arial, Helvetica, Geneva, Swiss, SunSans-Regular, sans-serif;
                    font-size: 10pt;
                    padding:5px;
                }
                .varsname {
                    font-weight:bold;
                }
                .showvars {
                    background:white;
                    border-style:dotted;
                    border-width:1px;
                    padding:2px;
                    font-family: Verdana, Arial, Helvetica, Geneva, Swiss, SunSans-Regular, sans-serif;
                    font-size:10pt;
                    font-weight:bold;"
                }
            </style>
            <style type="text/css" media="print">
                .showvars {
                    display:none;
                    visibility:invisible;
                }
            </style>
        ';

	print '<br />
            <div class="showvars">
            DEBUG <span style="color:red;font-weight:normal;font-size:12px;">(runtime: '.script_runtime().' sec)</span>
        ';

	//$vars_arr['script_globals'] = array('global script variables', '#7ACCC8');
	$vars_arr['_GET'] = array('$_GET', '#7DA7D9');
	$vars_arr['_POST'] = array('$_POST', '#F49AC1');
	$vars_arr['_FILES'] = array('$_FILES', '#82CA9C');
	$vars_arr['_SESSION'] = array('$_SESSION', '#FCDB26');
	$vars_arr['_COOKIE'] = array('$_COOKIE', '#A67C52');

	if($show_all_vars) {
		$vars_arr['_SERVER'] =  array('SERVER', '#A186BE');
		$vars_arr['_ENV'] =  array('ENV', '#7ACCC8');
	}

	foreach ($vars_arr as $vars_name => $vars_data) {
		if($vars_name != 'script_globals') global $$vars_name;
		if($$vars_name) {
			print '<div class="vars-container" style="background-color:'.$vars_data[1].';"><span class="varsname">'.$vars_data[0].'</span><br />';
			print_a($$vars_name, NULL, $show_object_vars, $limit);
			print '</div>';
		}
	}
	print '</div>';
}

/**
	 * @name pre
	 *
	 * @param string $string
	 * @param boolen $return_mode 是否输出 默认print
	 * @param numbers $tabwidth
	 * @return unknown
	 */
function pre( $string, $return_mode = false, $tabwidth = 3 ) {
	$tab = str_repeat('&nbsp;', $tabwidth);
	$string = preg_replace('/\t+/em', "str_repeat( ' ', strlen('\\0') * $tabwidth );", $string); /* replace all tabs with spaces */

	$out = '<pre>'.$string."</pre>\n";

	if($return_mode) {
		return $out;
	} else {
		print $out;
	}
}

function _check_for_leading_tabs( $string ) {
	return preg_match('/^\t/m', $string);
}

function _remove_exessive_leading_tabs( $string ) {
	/* remove whitespace lines at start of the string */
	$string = preg_replace('/^\s*\n/', '', $string);
	/* remove whitespace at end of the string */
	$string = preg_replace('/\s*$/', '', $string);

	# kleinste Anzahl von f�hrenden TABS z�hlen
	preg_match_all('/^\t+/', $string, $matches);
	$minTabCount = strlen(@min($matches[0]));

	# und entfernen
	$string = preg_replace('/^\t{'.$minTabCount.'}/m', '', $string);

	return $string;
}

/**
 * Debug helper function.  This is a wrapper for var_dump() that adds
 * the <pre /> tags, cleans up newlines and indents, and runs
 * htmlentities() before output.
 *
 * @param  mixed  $var The variable to dump.
 * @param  string $label An optional label.
 * @return string
 */
function dump($var, $label=null, $echo=true)
{
	// format the label
	$label = ($label===null) ? '' : rtrim($label) . ' ';

	// var_dump the variable into a buffer and keep the output
	ob_start();
	var_dump($var);
	$output = ob_get_clean();

	// neaten the newlines and indents
	$output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output);
	if (PHP_SAPI == 'cli') {
		$output = PHP_EOL . $label
		. PHP_EOL . $output
		. PHP_EOL;
	} else {
		$output = '<pre>'
		. $label
		. htmlspecialchars($output, ENT_QUOTES)
		//. htmlentities($output, ENT_QUOTES)
		. '</pre>';
	}

	if ($echo) {
		echo($output);
	}
	return $output;
}
?>